
package gov.jyy.xzxk.xksq.common.desensitization;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;
import java.util.Objects;


/**
 * 脱敏序列化器
 * <p>
 * 将  Java  对象序列化为  JSON  格式时，对属性进行脱敏处理的序列化器。
 */
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {
    private static final long serialVersionUID = -7868746622368564541L;
    private transient Desensitization<Object> desensitization;

    private transient boolean enableDesensitization = false;

    protected ObjectDesensitizeSerializer() {
        super(Object.class);
    }

    public Desensitization<Object> getDesensitization() {
        return desensitization;
    }

    public void setDesensitization(Desensitization<Object> desensitization) {
        this.desensitization = desensitization;
    }

    /**
     * `SerializerProvider`主要用来提供一些序列化所需的上下文信息，例如配置、序列化器等。
     * `BeanProperty`则代表了一个Java  Bean中的一个属性，它包含了该属性的相关信息，如名称、类型、注解等。
     * <p>
     * 该方法返回的是一个`JsonSerializer<?>`对象，它表示一个通用的`JsonSerializer`。
     * 这个通用的序列化器可以序列化任何类型的对象。
     * 而实际上，`createContextual`方法会创建一个具体类型的序列化器，该序列化器可以根据上下文信息的不同而变化。
     * 例如，当序列化一个Java  Bean时，可以根据BeanProperty的类型信息来创建一个相应类型的序列化器，从而实现对Bean属性的序列化。
     */
    @Override
    public JsonSerializer<Object> createContextual(SerializerProvider prov, BeanProperty property) {
        //  获取属性注解
        Desensitize annotation = property.getAnnotation(Desensitize.class);
        //  返回一个新的序列化器，用于对该属性进行脱敏
        return createContextual(annotation.desensitization());
    }

    @SuppressWarnings("unchecked")
    public JsonSerializer<Object> createContextual(Class<? extends Desensitization<?>> clazz) {
        //  创建一个新的序列化器
        ObjectDesensitizeSerializer serializer = new ObjectDesensitizeSerializer();
        if (clazz != DefaultDesensitization.class) {
            //  根据脱敏注解获取对应的脱敏器，赋值给序列化器
            serializer.setDesensitization((Desensitization<Object>) DesensitizationFactory.getDesensitization(clazz));
        }
        return serializer;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // 没有开启脱敏注解
        if(Objects.isNull(DesensitizationContext.<Boolean>getValue()) || DesensitizationContext.<Boolean>getValue() == Boolean.FALSE) {
            gen.writeObject(value);
            return;
        }
        Desensitization<Object> objectDesensitization = getDesensitization();
        if (objectDesensitization != null) {
            try {
                //  对属性进行脱敏后序列化
                gen.writeObject(objectDesensitization.desensitize(value));
            } catch (Exception e) {
                //  脱敏发生错误时，保留原值
                gen.writeObject(value);
            }
        } else if (value instanceof String) {
            //  如果属性没有对应的脱敏注解，对字符串进行默认脱敏处理
            gen.writeString(Symbol.getSymbol(((String) value).length(), Symbol.STAR));
        } else {
            //  如果属性既没有对应的脱敏注解，也不是字符串类型，直接序列化
            gen.writeObject(value);
        }
    }
}
